package com.tsfyun.scm.service.impl.customer;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.tsfyun.common.base.enums.AgencyFeeModeEnum;
import com.tsfyun.common.base.enums.AgreeModeEnum;
import com.tsfyun.common.base.enums.QuoteTypeEnum;
import com.tsfyun.common.base.enums.TaxTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.scm.dto.customer.ImpQuoteDTO;
import com.tsfyun.scm.entity.customer.ImpQuote;
import com.tsfyun.scm.mapper.customer.ImpQuoteMapper;
import com.tsfyun.scm.service.customer.ICustomerExpressQuoteService;
import com.tsfyun.scm.service.customer.IImpQuoteService;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.scm.util.AgreementUtil;
import com.tsfyun.scm.util.TsfWeekendSqls;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 进口报价 服务实现类
 * </p>
 *
 *
 * @since 2020-04-01
 */
@Service
@Slf4j
public class ImpQuoteServiceImpl extends ServiceImpl<ImpQuote> implements IImpQuoteService {

    @Autowired
    private ImpQuoteMapper impQuoteMapper;

    @Autowired
    private ICustomerExpressQuoteService customerExpressQuoteService;

    @Override
    public List<ImpQuote> findByAgreementId(Long agreementId) {
        List<ImpQuote> list = impQuoteMapper.selectByExample(Example.builder(ImpQuote.class).where(TsfWeekendSqls.<ImpQuote>custom().andEqualTo(false,ImpQuote::getAgreementId,agreementId)).build());
        //按报价类型升序排
        if(CollectionUtil.isNotEmpty(list)) {
            list = list.stream().sorted(Comparator.comparing(ImpQuote::getQuoteType)).collect(Collectors.toList());
        }
        return list;
    }

    @Override
    public String quoteDescribe(List<ImpQuote> impQuotes) {
        StringBuffer sb = new StringBuffer("");
        if(CollUtil.isNotEmpty(impQuotes)){
            for(int i=0;i<impQuotes.size();i++){
                ImpQuote dto = impQuotes.get(i);
                sb.append("【"+(i+1)+"】");
                sb.append(quoteDescribe(dto));
            }
        }
        return sb.toString();
    }

    @Override
    public String quoteDescribe(ImpQuote dto) {
        StringBuffer sb = new StringBuffer("");
        sb.append(QuoteTypeEnum.of(dto.getQuoteType()).getName());
        sb.append("【");
        AgreeModeEnum agreeModeEnum = AgreeModeEnum.of(dto.getAgreeMode());
        StringBuffer quote = new StringBuffer("");
        quote.append(agreeModeEnum.getName()+" ");
        switch (agreeModeEnum){
            case IMPORT_DAY:
                quote.append(dto.getDay()+"天");
                break;
            case PAYMENT_DAY:
                quote.append(dto.getDay()+"天");
                break;
            case MONTH:
                quote.append(AgreementUtil.formatMonthDescribe(dto.getMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getMonthDay()));
                break;
            case HALF_MONTH:
                quote.append("1号到15号:" + AgreementUtil.formatMonthDescribe(dto.getFirstMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getFirstMonthDay()));
                quote.append(" 16号到月末:"+ AgreementUtil.formatMonthDescribe(dto.getLowerMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getLowerMonthDay()));
                break;
            case WEEK:
                quote.append(AgreementUtil.formatWeekDescribe(dto.getWeek()) + AgreementUtil.formatWeekDayDescribe(dto.getWeekDay()));
                break;
        }
        AgreeModeEnum taxAgreeModeEnum = AgreeModeEnum.of(dto.getTaxAgreeMode());
        StringBuffer taxQuote = new StringBuffer("");
        taxQuote.append(taxAgreeModeEnum.getName()+" ");
        switch (taxAgreeModeEnum){
            case IMPORT_DAY:
                taxQuote.append(dto.getTaxDay()+"天");
                break;
            case PAYMENT_DAY:
                taxQuote.append(dto.getTaxDay()+"天");
                break;
            case MONTH:
                taxQuote.append(AgreementUtil.formatMonthDescribe(dto.getTaxMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getTaxMonthDay()));
                break;
            case HALF_MONTH:
                taxQuote.append("1号到15号:" + AgreementUtil.formatMonthDescribe(dto.getTaxFirstMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getTaxFirstMonthDay()));
                taxQuote.append(" 16号到月末:"+ AgreementUtil.formatMonthDescribe(dto.getTaxLowerMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getTaxLowerMonthDay()));
                break;
            case WEEK:
                taxQuote.append(AgreementUtil.formatWeekDescribe(dto.getTaxWeek()) + AgreementUtil.formatWeekDayDescribe(dto.getTaxWeekDay()));
                break;
        }

        AgreeModeEnum goAgreeModeEnum = AgreeModeEnum.of(dto.getGoAgreeMode());
        StringBuffer goQuote = new StringBuffer("");
        goQuote.append(goAgreeModeEnum.getName()+" ");
        switch (goAgreeModeEnum){
            case IMPORT_DAY:
                goQuote.append(dto.getGoDay()+"天");
                break;
            case PAYMENT_DAY:
                goQuote.append(dto.getGoDay()+"天");
                break;
            case MONTH:
                goQuote.append(AgreementUtil.formatMonthDescribe(dto.getGoMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getGoMonthDay()));
                break;
            case HALF_MONTH:
                goQuote.append("1号到15号:" + AgreementUtil.formatMonthDescribe(dto.getGoFirstMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getGoFirstMonthDay()));
                goQuote.append(" 16号到月末:"+ AgreementUtil.formatMonthDescribe(dto.getGoLowerMonth()) + AgreementUtil.formatMonthDayDescribe(dto.getGoLowerMonthDay()));
                break;
            case WEEK:
                goQuote.append(AgreementUtil.formatWeekDescribe(dto.getGoWeek()) + AgreementUtil.formatWeekDayDescribe(dto.getGoWeekDay()));
                break;
        }
        sb.append("代杂费账期：");
        sb.append(quote);

        if(!quote.toString().equals(taxQuote.toString())){
            sb.append(" 税款账期：");
            sb.append(taxQuote);
        }
        if(!quote.toString().equals(goQuote.toString())){
            sb.append(" 货款账期：");
            sb.append(goQuote);
        }

        sb.append("】");
        sb.append("宽限天数:"+dto.getGraceDay()+"天");
        sb.append(" 逾期利率:"+dto.getOverdueRate()+"%/天");
        if(Objects.equals(AgencyFeeModeEnum.STANDARD,AgencyFeeModeEnum.of(dto.getAgencyFeeMode()))) {
            sb.append(",代理费:"+ TaxTypeEnum.of(dto.getTaxType()).getName()+" "+dto.getBasePrice()+"/单 +"+dto.getServiceRate()+"%");
            sb.append(" 最低收费:"+dto.getMinCost());
            sb.append(dto.getTaxIncluded()?" 加税点":" 不加税点");
        } else if (Objects.equals(AgencyFeeModeEnum.EXPRESS,AgencyFeeModeEnum.of(dto.getAgencyFeeMode()))) {
            sb.append(",代理费:"+ AgencyFeeModeEnum.of(dto.getAgencyFeeMode()).getName());
        }
        return sb.toString();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveImpQuotes(Long agreementId,Long customerId,List<ImpQuoteDTO> impQuotes) {
        //根据协议查询所有报价
        ImpQuote query = new ImpQuote();
        query.setAgreementId(agreementId);
        List<ImpQuote> impQuoteList = super.list(query);
        Map<Long,ImpQuote> impQuoteMap = new LinkedHashMap<>();
        impQuoteList.stream().forEach(impQuote ->{
            impQuoteMap.put(impQuote.getId(),impQuote);
        });
        if(CollUtil.isNotEmpty(impQuotes)){
            for(ImpQuoteDTO dto : impQuotes){
                ImpQuote impQuote = null;
                if(Objects.nonNull(dto.getId())){
                    impQuote = impQuoteMap.get(dto.getId());
                    TsfPreconditions.checkArgument(Objects.nonNull(impQuote),new ServiceException(String.format("当前协议【%s】不存在,请刷新页面重试！",QuoteTypeEnum.of(dto.getQuoteType()).getName())));
                    impQuoteMap.remove(impQuote.getId());
                }else{
                    impQuote = new ImpQuote();
                    impQuote.setAgreementId(agreementId);
                    impQuote.setQuoteType(dto.getQuoteType());
                }
                //初始化报价数据
                initAssignment(impQuote);
                QuoteTypeEnum quoteTypeEnum = QuoteTypeEnum.of(impQuote.getQuoteType());
                switch (quoteTypeEnum){
                    case PAD_TAX://垫税款
                        fullPeriod(impQuote,dto);
                        fullTaxPeriod(impQuote,dto);
                        break;
                    case PAD_GOOD://垫货款
                        fullPeriod(impQuote,dto);
                        fullTaxPeriod(impQuote,dto);
                        fullGoodPeriod(impQuote,dto);
                        break;
                    case ADVANCE_CHARGE://预付款

                        break;
                }
                impQuote.setTaxType(dto.getTaxType());
                impQuote.setTaxIncluded(Objects.equals(Boolean.TRUE,dto.getTaxIncluded())?true:false);
                impQuote.setBasePrice(dto.getBasePrice());
                impQuote.setServiceRate(dto.getServiceRate());
                impQuote.setMinCost(dto.getMinCost());
                impQuote.setGraceDay(dto.getGraceDay());
                impQuote.setOverdueRate(dto.getOverdueRate());
                //是否加税点
                impQuote.setTaxIncluded(dto.getTaxIncluded());
                //代理费计算模式
                impQuote.setAgencyFeeMode(dto.getAgencyFeeMode());

                //如果是按重量计费，则需要查询当前配置的报价
                if(Objects.equals(impQuote.getAgencyFeeMode(), AgencyFeeModeEnum.EXPRESS.getCode())) {
                    //税前
                    impQuote.setTaxType(TaxTypeEnum.AFTER_TAX.getCode());
                    //按单收费
                    impQuote.setBasePrice(BigDecimal.ZERO);
                    //收费比例
                    impQuote.setServiceRate(BigDecimal.ZERO);
                    //最低收费
                    impQuote.setMinCost(BigDecimal.ZERO);
                }
                if(Objects.isNull(impQuote.getId())){
                    //新增
                    super.saveNonNull(impQuote);
                }else{
                    //修改
                    super.updateById(impQuote);
                }
            }
        }
        for(Map.Entry<Long,ImpQuote> impQuoteEntry : impQuoteMap.entrySet()){
            try{
                super.removeById(impQuoteEntry.getKey());
            } catch (DataIntegrityViolationException e) {
                throw new ServiceException(String.format("当前协议【%s】业务已被使用禁止取消！",QuoteTypeEnum.of(impQuoteEntry.getValue().getQuoteType()).getName()));
            }
        }
    }

    @Override
    public void deleteByAgreementId(Long agreementId) {
        try{
            impQuoteMapper.deleteByAgreementId(agreementId);
        } catch (DataIntegrityViolationException e) {
            throw new ServiceException("当前协议报价已被引用禁止删除");
        }
    }

    @Override
    public ImpQuote initBaseQuote() {
        ImpQuote impQuote = new ImpQuote();
        impQuote.setQuoteType(QuoteTypeEnum.ADVANCE_CHARGE.getCode());// 预付款
        impQuote.setAgreeMode(AgreeModeEnum.IMPORT_DAY.getCode());//进口日
        impQuote.setDay(0);
        impQuote.setMonth(0);
        impQuote.setMonthDay(0);
        impQuote.setFirstMonth(0);
        impQuote.setFirstMonthDay(0);
        impQuote.setLowerMonth(0);
        impQuote.setLowerMonthDay(0);
        impQuote.setWeek(0);
        impQuote.setWeekDay(0);
        impQuote.setTaxAgreeMode(AgreeModeEnum.IMPORT_DAY.getCode());
        impQuote.setTaxDay(0);
        impQuote.setTaxMonth(0);
        impQuote.setTaxMonthDay(0);
        impQuote.setTaxFirstMonth(0);
        impQuote.setTaxFirstMonthDay(0);
        impQuote.setTaxLowerMonth(0);
        impQuote.setTaxLowerMonthDay(0);
        impQuote.setTaxWeek(0);
        impQuote.setTaxWeekDay(0);
        impQuote.setGoAgreeMode(AgreeModeEnum.PAYMENT_DAY.getCode());
        impQuote.setGoDay(0);
        impQuote.setGoMonth(0);
        impQuote.setGoMonthDay(0);
        impQuote.setGoFirstMonth(0);
        impQuote.setGoFirstMonthDay(0);
        impQuote.setGoLowerMonth(0);
        impQuote.setGoLowerMonthDay(0);
        impQuote.setGoWeek(0);
        impQuote.setGoWeekDay(0);
        impQuote.setTaxType(TaxTypeEnum.AFTER_TAX.getCode());
        impQuote.setTaxIncluded(Boolean.TRUE);//加税点
        impQuote.setBasePrice(BigDecimal.ZERO);
        impQuote.setServiceRate(BigDecimal.ZERO);
        impQuote.setMinCost(BigDecimal.ZERO);
        impQuote.setGraceDay(0);
        impQuote.setOverdueRate(BigDecimal.ZERO);
        impQuote.setAgencyFeeMode(AgencyFeeModeEnum.EXPRESS.getCode());//按重量计费
        return impQuote;
    }

    private void fullPeriod(ImpQuote impQuote,ImpQuoteDTO dto){
        AgreeModeEnum agreeMode = AgreeModeEnum.of(dto.getAgreeMode());
        impQuote.setAgreeMode(agreeMode.getCode());
        switch (agreeMode){
            case IMPORT_DAY://进口日
                impQuote.setDay(dto.getDay());
                break;
            case PAYMENT_DAY://付款日
                impQuote.setDay(dto.getDay());
                break;
            case MONTH://月结
                impQuote.setMonth(dto.getMonth());
                impQuote.setMonthDay(dto.getMonthDay());
                break;
            case HALF_MONTH://半月结
                impQuote.setFirstMonth(dto.getFirstMonth());
                impQuote.setFirstMonthDay(dto.getFirstMonthDay());
                impQuote.setLowerMonth(dto.getLowerMonth());
                impQuote.setLowerMonthDay(dto.getLowerMonthDay());
                break;
            case WEEK://周结
                impQuote.setWeek(dto.getWeek());
                impQuote.setWeekDay(dto.getWeekDay());
                break;
        }
    }

    private void fullTaxPeriod(ImpQuote impQuote,ImpQuoteDTO dto){
        if(Objects.equals(Boolean.TRUE,dto.getTaxFit())){
            impQuote.setTaxAgreeMode(impQuote.getAgreeMode());
            impQuote.setTaxDay(impQuote.getDay());
            impQuote.setTaxMonth(impQuote.getMonth());
            impQuote.setTaxMonthDay(impQuote.getMonthDay());
            impQuote.setTaxFirstMonth(impQuote.getFirstMonth());
            impQuote.setTaxFirstMonthDay(impQuote.getFirstMonthDay());
            impQuote.setTaxLowerMonth(impQuote.getLowerMonth());
            impQuote.setTaxLowerMonthDay(impQuote.getLowerMonthDay());
            impQuote.setTaxWeek(impQuote.getWeek());
            impQuote.setTaxWeekDay(impQuote.getWeekDay());
            return;
        }
        AgreeModeEnum agreeMode = AgreeModeEnum.of(dto.getTaxAgreeMode());
        impQuote.setTaxAgreeMode(agreeMode.getCode());
        switch (agreeMode){
            case IMPORT_DAY://进口日
                impQuote.setTaxDay(dto.getTaxDay());
                break;
            case PAYMENT_DAY://付款日
                impQuote.setTaxDay(dto.getTaxDay());
                break;
            case MONTH://月结
                impQuote.setTaxMonth(dto.getTaxMonth());
                impQuote.setTaxMonthDay(dto.getTaxMonthDay());
                break;
            case HALF_MONTH://半月结
                impQuote.setTaxFirstMonth(dto.getTaxFirstMonth());
                impQuote.setTaxFirstMonthDay(dto.getTaxFirstMonthDay());
                impQuote.setTaxLowerMonth(dto.getTaxLowerMonth());
                impQuote.setTaxLowerMonthDay(dto.getTaxLowerMonthDay());
                break;
            case WEEK://周结
                impQuote.setTaxWeek(dto.getTaxWeek());
                impQuote.setTaxWeekDay(dto.getTaxWeekDay());
                break;
        }
    }
    //货款数据
    private void fullGoodPeriod(ImpQuote impQuote,ImpQuoteDTO dto){
        if(Objects.equals(Boolean.TRUE,dto.getGoodFit())){
            //进口日
            if(AgreeModeEnum.IMPORT_DAY.getCode().equals(impQuote.getAgreeMode())){
                impQuote.setGoAgreeMode(AgreeModeEnum.PAYMENT_DAY.getCode());
            }else{
                impQuote.setGoAgreeMode(impQuote.getAgreeMode());
            }
            impQuote.setGoDay(impQuote.getDay());
            impQuote.setGoMonth(impQuote.getMonth());
            impQuote.setGoMonthDay(impQuote.getMonthDay());
            impQuote.setGoFirstMonth(impQuote.getFirstMonth());
            impQuote.setGoFirstMonthDay(impQuote.getFirstMonthDay());
            impQuote.setGoLowerMonth(impQuote.getLowerMonth());
            impQuote.setGoLowerMonthDay(impQuote.getLowerMonthDay());
            impQuote.setGoWeek(impQuote.getWeek());
            impQuote.setGoWeekDay(impQuote.getWeekDay());
            return;
        }
        AgreeModeEnum agreeMode = AgreeModeEnum.of(dto.getGoAgreeMode());
        impQuote.setGoAgreeMode(agreeMode.getCode());
        switch (agreeMode){
            case IMPORT_DAY://进口日
                impQuote.setGoDay(dto.getGoDay());
                break;
            case PAYMENT_DAY://付款日
                impQuote.setGoDay(dto.getGoDay());
                break;
            case MONTH://月结
                impQuote.setGoMonth(dto.getGoMonth());
                impQuote.setGoMonthDay(dto.getGoMonthDay());
                break;
            case HALF_MONTH://半月结
                impQuote.setGoFirstMonth(dto.getGoFirstMonth());
                impQuote.setGoFirstMonthDay(dto.getGoFirstMonthDay());
                impQuote.setGoLowerMonth(dto.getGoLowerMonth());
                impQuote.setGoLowerMonthDay(dto.getGoLowerMonthDay());
                break;
            case WEEK://周结
                impQuote.setGoWeek(dto.getGoWeek());
                impQuote.setGoWeekDay(dto.getGoWeekDay());
                break;
        }
    }

    private void initAssignment(ImpQuote impQuote){
        impQuote.setAgreeMode(AgreeModeEnum.IMPORT_DAY.getCode());
        impQuote.setTaxAgreeMode(AgreeModeEnum.IMPORT_DAY.getCode());
        impQuote.setGoAgreeMode(AgreeModeEnum.PAYMENT_DAY.getCode());

        impQuote.setDay(0);
        impQuote.setMonth(0);
        impQuote.setMonthDay(0);
        impQuote.setFirstMonth(0);
        impQuote.setFirstMonthDay(0);
        impQuote.setLowerMonth(0);
        impQuote.setLowerMonthDay(0);
        impQuote.setWeek(0);
        impQuote.setWeekDay(0);

        impQuote.setTaxDay(0);
        impQuote.setTaxMonth(0);
        impQuote.setTaxMonthDay(0);
        impQuote.setTaxFirstMonth(0);
        impQuote.setTaxFirstMonthDay(0);
        impQuote.setTaxLowerMonth(0);
        impQuote.setTaxLowerMonthDay(0);
        impQuote.setTaxWeek(0);
        impQuote.setTaxWeekDay(0);

        impQuote.setGoDay(0);
        impQuote.setGoMonth(0);
        impQuote.setGoMonthDay(0);
        impQuote.setGoFirstMonth(0);
        impQuote.setGoFirstMonthDay(0);
        impQuote.setGoLowerMonth(0);
        impQuote.setGoLowerMonthDay(0);
        impQuote.setGoWeek(0);
        impQuote.setGoWeekDay(0);
    }

}
